import typing

import pydantic
from redis.asyncio import Redis

import lib.app.settings as app_settings
import lib.clients.base_cache_provider as base_cache_provider


class AsyncRedisClient(base_cache_provider.BaseCacheProvider):
    def __init__(self, settings: app_settings.Settings) -> None:
        self.settings = settings
        self.client: Redis = Redis(
            host=self.settings.cache.host,
            port=self.settings.cache.port,
            db=self.settings.cache.db,
        )

    async def dispose_callback(self) -> None:
        await self.client.close()

    async def get_by_id(self, key: str, model_name: typing.Type[pydantic.BaseModel]) -> pydantic.BaseModel | None:
        """
        Получает список объектов модели из кеша.

        :param key: ключ для доступа к кешу
        :param model_name: класс модели данных
        :return: список объектов модели или None, если данных нет в кеше
        """

        data = await self.client.get(key)
        if not data:
            return None
        return model_name.parse_raw(data)

    async def get_many_ids(
        self, keys: list[str], model_name: typing.Type[pydantic.BaseModel]
    ) -> list[pydantic.BaseModel] | None:
        datas = await self.client.mget(keys)
        return [model_name.parse_raw(data) for data in datas if data]

    async def put_by_id(self, key: str, data: pydantic.BaseModel) -> None:
        await self.client.set(key, data.json(), self.settings.cache.CACHE_EXPIRE)

    async def put_many_ids(self, data: dict[str, pydantic.BaseModel]) -> None:
        await self.client.mset({key: value.json() for key, value in data.items()})
        [await self.client.expire(key, self.settings.cache.CACHE_EXPIRE) for key in data.keys()]
